package com.example.delivery;

import lombok.Getter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.HashMap;
import java.util.Map;

@SpringBootApplication
@EnableConfigurationProperties(DeliveryApplication.BaiduMapConfig.class)
public class DeliveryApplication {

    public static void main(String[] args) {
        SpringApplication.run(DeliveryApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    @Getter
    @ConfigurationProperties(prefix = "baidu.map")
    public static class BaiduMapConfig {
        private String apiKey;
        private double maxDistance = 50.0; // 默认最大配送距离50km

        public void setApiKey(String apiKey) {
            this.apiKey = apiKey;
        }

        public void setMaxDistance(double maxDistance) {
            this.maxDistance = maxDistance;
        }
    }

    // 请求DTO
    @Getter
    static class DeliveryCheckRequest {
        private String fromAddress;
        private String toAddress;

        public void setFromAddress(String fromAddress) {
            this.fromAddress = fromAddress;
        }

        public void setToAddress(String toAddress) {
            this.toAddress = toAddress;
        }
    }

    // 响应DTO
    @Getter
    static class DeliveryCheckResponse {
        // Getters for JSON serialization
        private final boolean allowDelivery;
        private final double distance;
        private final String message;

        public DeliveryCheckResponse(boolean allowDelivery, double distance, String message) {
            this.allowDelivery = allowDelivery;
            this.distance = distance;
            this.message = message;
        }

    }

    // 地理位置实体
    @Getter
    static class Location {
        private final double lng;
        private final double lat;

        public Location(double lng, double lat) {
            this.lng = lng;
            this.lat = lat;
        }

        public String toCoordinateString() {
            return lat + "," + lng;
        }
    }

    @RestController
    @RequestMapping("/api/delivery")
    static class DeliveryController {
        private final RestTemplate restTemplate;
        private final BaiduMapConfig config;

        public DeliveryController(RestTemplate restTemplate, BaiduMapConfig config) {
            this.restTemplate = restTemplate;
            this.config = config;
        }

        @PostMapping("/check")
        public ResponseEntity<DeliveryCheckResponse> checkDelivery(@RequestBody DeliveryCheckRequest request) {
            try {
                // 1. 地址转经纬度
                Location from = geocode(request.getFromAddress());
                Location to = geocode(request.getToAddress());

                // 2. 计算距离
                double distance = calculateDistance(from, to);

                // 3. 判断是否可配送
                boolean allow = distance <= config.getMaxDistance();

                return ResponseEntity.ok(new DeliveryCheckResponse(
                        allow,
                        distance,
                        allow ? "可配送" : "超出配送范围（最大" + config.getMaxDistance() + "km）"
                ));
            } catch (Exception e) {
                return ResponseEntity.status(500)
                        .body(new DeliveryCheckResponse(false, 0.0, "服务异常：" + e.getMessage()));
            }
        }

        private Location geocode(String address) {
            Map<String, String> params = new HashMap<>();
            params.put("address", address);
            params.put("output", "json");
            params.put("ak", config.getApiKey());

            String url = buildUrl("https://api.map.baidu.com/geocoding/v3/", params);
            Map response = restTemplate.getForObject(url, Map.class);

            if (response == null || !"0".equals(response.get("status").toString())) {
                throw new RuntimeException("地址解析失败：" + address);
            }

            Map<String, Object> location = (Map<String, Object>) ((Map<String, Object>) response.get("result")).get("location");
            return new Location(
                    Double.parseDouble(location.get("lng").toString()),
                    Double.parseDouble(location.get("lat").toString())
            );
        }

        private double calculateDistance(Location from, Location to) {
            Map<String, String> params = new HashMap<>();
            params.put("origins", from.toCoordinateString());
            params.put("destinations", to.toCoordinateString());
            params.put("output", "json");
            params.put("ak", config.getApiKey());

            String url = buildUrl("https://api.map.baidu.com/routematrix/v2/driving", params);
            Map response = restTemplate.getForObject(url, Map.class);

            if (response == null || !"0".equals(response.get("status").toString())) {
                throw new RuntimeException("距离计算失败");
            }

            Map<String, Object> result = (Map<String, Object>) ((Map<String, Object>) response.get("result")).get("elements");
            Map<String, Object> distanceInfo = (Map<String, Object>) result.get(0);
            return Double.parseDouble(((Map<String, Object>) distanceInfo.get("distance")).get("value").toString()) / 1000.0; // 转换为千米
        }

        private String buildUrl(String baseUrl, Map<String, String> params) {
            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl);
            params.forEach(builder::queryParam);
            return builder.toUriString();
        }
    }
}